%%% Copyright 2010 Google Inc.
%%%
%%% Licensed under the Apache License, Version 2.0 (the "License");
%%% you may not use this file except in compliance with the License.
%%% You may obtain a copy of the License at
%%%
%%%     http://www.apache.org/licenses/LICENSE-2.0
%%%
%%% Unless required by applicable law or agreed to in writing, software
%%% distributed under the License is distributed on an "AS IS" BASIS,
%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%%% See the License for the specific language governing permissions and
%%% limitations under the License.

%%% @copyright 2010 Google Inc. All Rights Reserved.
%%% @author <jacoby@google.com> Jacoby Thwaites [http://sites/madcloud]
%%% @version {@version}
%%% @doc
%%% Mock prog module for testing dependencies such as prog_srv.
%%%
%%% @headerfile "../include/txm.hrl"

-module(prog_mock).

-compile(export_all).

%% Generates an ID.
-define(RANDOM_ID, now()).
-define(RANDOM_REF(Type), {Type, ?RANDOM_ID}).

-include("txm.hrl").

%%% Client functions
-export([create_tables/0, init/0]).
-export([get_root_ref/0, get_root_ref/1, record_to_ref/1]).
-export([resolve_absolute/1, resolve_relative/2, resolve_scoped/2]).
-export([get_record/1]).
-export([new_record/3]).
-export([snapshot/1, snapshot/2]).
-export([get_shallow_index/1, get_deep_index/1]).
-export([get_shallow_contents/1, get_deep_contents/1]).

%% Pretends to init.
init() -> ?OK_RETURN.

%% Pretends to create tables.
create_tables() -> ?OK_RETURN.

%% Returns root folder reference.
get_root_ref() -> ?OK_RETURN(?ROOT_FOLDER_REF).

%% Returns random program root folder reference
get_root_ref(_Any) -> ?OK_RETURN(?RANDOM_REF(?FOLDER)).

%% Returns random ref based on first part of path
%% Name resolution.
resolve_absolute("/") -> {ok, {folder, {0, 0, 0}}};
resolve_absolute("/mock") -> {ok, {folder, {0, 0, 1}}};
resolve_absolute("/mock/Primes") -> {ok, {op, {20, 0, 100}}}.

resolve_scoped(_Ref, _Name) ->
  {ok, {op, {0, 0, 0}}}.

resolve_relative(Folder, "") ->
  {ok, Folder};
resolve_relative(_Folder, "backend") ->
  {ok, {folder, {0, 0, 2}}}.

%% ----------------------------------------------------------------------------
%% Returns fixed records that look sensible, being:
%% Root folder
%% Folder '/mock'
%% Composite null op '/mock/Primes'
%% In Primes root folder:
%%   fields 'n', 'YES', 'NO'
%%   ops 'Start', 'ShowPrime', 'ShowNotPrime'
%%   folder 'backend'
%%   In backend folder:
%%     ops 'FirstDivisor', 'Test', 'Iterate'
%% In Primes version #1 labelled 'Version 1'
%%   contents as per root folder.
%% ----------------------------------------------------------------------------

%% Root folder.
get_record({folder, {0, 0, 0}}) ->
  R = #?FOLDER{id = {0, 0, 0},
               entries = nr_set:from_proplist(
                           [{"mock", {folder, {0, 0, 1}}}])},
  ?OK_RETURN(R);

%% Folder '/mock'
get_record({folder, {0, 0, 1}}) ->
  R = #?FOLDER{id = {0, 0, 1},
               entries = nr_set:from_proplist(
                           [{"..", {folder, {0, 0, 0}}},
                            {"Primes", {op, {20, 0, 100}}}])},
  ?OK_RETURN(R);

%% Composite op '/mock/Primes' with root folder and one version.
get_record({op, Id = {20, 0, 100}}) ->
  Mask = nr_set:new(),
  Input = nr_set:new(),
  Outputs = nr_set_dict:new(),
  R = #?OP{id = Id,
           mask = Mask,
           input = Input,
           outputs = Outputs,
           isComposite = true,
           rootFolderRef = {folder, {0, 20, 1}},
           versions = [{1, "Version 1", {folder, {0, 20, 2}}}],
           opType = ?OP_TYPE_NULL
       },
       ?OK_RETURN(R);

%% Composite op's root folder.
get_record({folder, {0, 20, 1}}) ->
  R = #?FOLDER{id = {0, 20, 1},
           entries = nr_set:from_proplist(
                       [{"..", {folder, {0, 0, 1}}},
                        {"YES", {field, {10, 0, 1}}},
                        {"NO", {field, {10, 0, 2}}},
                        {"n", {field, {10, 0, 3}}},
                        {"Start", {op, {20, 0, 1}}},
                        {"ShowPrime", {op, {20, 0, 2}}},
                        {"ShowNotPrime", {op, {20, 0, 3}}},
                        {"backend", {folder, {0, 0, 2}}}
                       ])},
  ?OK_RETURN(R);

%% Backend folder under composite op root.
get_record({folder, {0, 0, 2}}) ->
  R = #?FOLDER{id = {0, 0, 2},
           entries = nr_set:from_proplist(
                       [{"..", {folder, {0, 20, 1}}},
                        {"div", {field, {10, 0, 4}}},
                        {"MAYBE", {field, {10, 0, 5}}},
                        {"FirstDivisor", {op, {20, 0, 4}}},
                        {"Test", {op, {20, 0, 5}}},
                        {"Iterate", {op, {20, 0, 6}}}
                       ])},
  ?OK_RETURN(R);

%% Mock fields.
%% #1
get_record({field, {10, 0, 1}}) ->
  R = #?FIELD{id = {10, 0, 1},
          type = flag},
  ?OK_RETURN(R);

%% #2
get_record({field, {10, 0, 2}}) ->
  R = #?FIELD{id = {10, 0, 2},
          type = flag},
  ?OK_RETURN(R);

%% #3
get_record({field, {10, 0, 3}}) ->
  R = #?FIELD{id = {10, 0, 3},
          type = integer},
  ?OK_RETURN(R);

%% #4
get_record({field, {10, 0, 4}}) ->
  R = #?FIELD{id = {10, 0, 4},
          type = integer},
  ?OK_RETURN(R);

%% #5
get_record({field, {10, 0, 5}}) ->
  R = #?FIELD{id = {10, 0, 5},
          type = flag},
  ?OK_RETURN(R);

%% Mock ops.
%% #1
get_record({op, Id = {20, 0, 1}}) ->
  Mask = nr_set:new(),
  Input = nr_set:new(),
  Outputs = nr_set_dict:from_proplist(
              [{"Start",
                [{"n", {field, {10, 0, 3}}}]}]),
  R = #?OP{id = Id,
           mask = Mask,
           input = Input,
           outputs = Outputs,
           opType = ?OP_TYPE_N
       },
  ?OK_RETURN(R);

%% #2
get_record({op, Id = {20, 0, 2}}) ->
  Mask = nr_set:new(),
  Input = nr_set:from_proplist(
            [{"n", {field, {10, 0, 3}}},
             {"YES", {field, {10, 0, 1}}}]),
  Outputs = nr_set_dict:new(),
  R = #?OP{id = Id,
           mask = Mask,
           input = Input,
           outputs = Outputs,
           opType = ?OP_TYPE_OO
       },
  ?OK_RETURN(R);

%% #3
get_record({op, Id = {20, 0, 3}}) ->
  Mask = nr_set:new(),
  Input = nr_set:from_proplist(
            [{"n", {field, {10, 0, 3}}},
             {"NO", {field, {10, 0, 2}}}]),
  Outputs = nr_set_dict:new(),
  R = #?OP{id = Id,
           mask = Mask,
           input = Input,
           outputs = Outputs,
           opType = ?OP_TYPE_OO
       },
  ?OK_RETURN(R);

%% #4
get_record({op, Id = {20, 0, 4}}) ->
  Mask = nr_set:new(),
  Input = nr_set:from_proplist(
            [{"n", {field, {10, 0, 3}}}]),
  Outputs = nr_set_dict:from_proplist(
              [{"Divisor",
                [{"div", {field, {10, 0, 4}}}]}]),
  R = #?OP{id = Id,
           mask = Mask,
           input = Input,
           outputs = Outputs,
           opType = ?OP_TYPE_RR
       },
  ?OK_RETURN(R);

%% #5
get_record({op, Id = {20, 0, 5}}) ->
  Mask = nr_set:new(),
  Input = nr_set:from_proplist(
            [{"n", {field, {10, 0, 3}}},
             {"div", {field, {10, 0, 4}}}]),
  Outputs = nr_set_dict:from_proplist(
              [{"Yes",
                [{"YES", {field, {10, 0, 1}}}]},
               {"No",
                [{"NO", {field, {10, 0, 2}}}]},
               {"Maybe",
                [{"MAYBE", {field, {10, 0, 5}}}]}]),
  R = #?OP{id = Id,
           mask = Mask,
           input = Input,
           outputs = Outputs,
           opType = ?OP_TYPE_RR
       },
  ?OK_RETURN(R);

%% #6
get_record({op, Id = {20, 0, 6}}) ->
  Mask = nr_set:new(),
  Input = nr_set:from_proplist(
            [{"MAYBE", {field, {10, 0, 5}}},
             {"n", {field, {10, 0, 3}}},
             {"div", {field, {10, 0, 4}}}]),
  Outputs = nr_set_dict:from_proplist(
              [{"Iterate",
                [{"n", {field, {10, 0, 3}}},
                 {"div", {field, {10, 0, 4}}}]}]),
  R = #?OP{id = Id,
           mask = Mask,
           input = Input,
           outputs = Outputs,
           opType = ?OP_TYPE_IRR
       },
  ?OK_RETURN(R);

%% All other refs return a random record.
get_record({op, Id}) ->
  ?OK_RETURN(#?OP{id = Id});

get_record({field, Id}) ->
  ?OK_RETURN(#?FIELD{id = Id});

get_record({folder, Id}) ->
  ?OK_RETURN(#?FOLDER{id = Id}).

%% Mock shallow and deep indexes.
get_shallow_index({folder, {0, 20, 1}}) ->
  R = {index, [{id, {0, 20, 1}}],
       [{folder, [{name, ".."}, {id, {0, 0, 1}}]},
        {field, [{name, "YES"}, {id, {10, 0, 1}}]},
        {field, [{name, "NO"}, {id, {10, 0, 2}}]},
        {field, [{name, "n"}, {id, {10, 0, 3}}]},
        {op, [{name, "Start"}, {id, {20, 0, 1}}]},
        {op, [{name, "ShowPrime"}, {id, {20, 0, 2}}]},
        {op, [{name, "ShowNotPrime"}, {id, {20, 0, 3}}]}
         ]},
  ?OK_RETURN(R);

get_shallow_index({folder, {0, 0, 2}}) ->
  R = {index, [{id, {0, 0, 2}}],
       [{folder, [{name, ".."}, {id, {0, 20, 1}}]},
        {field, [{name, "div"}, {id, {10, 0, 4}}]},
        {field, [{name, "MAYBE"}, {id, {10, 0, 5}}]},
        {op, [{name, "FirstDivisor"}, {id, {20, 0, 4}}]},
        {op, [{name, "Test"}, {id, {20, 0, 5}}]},
        {op, [{name, "Iterate"}, {id, {20, 0, 6}}]}
         ]},
  ?OK_RETURN(R).

get_deep_index({folder, {0, 20, 1}}) ->
  R = {index, [{id, {0, 20, 1}}],
       [{field, [{name, "YES"}, {id, {10, 0, 1}}]},
        {field, [{name, "NO"}, {id, {10, 0, 2}}]},
        {field, [{name, "n"}, {id, {10, 0, 3}}]},
        {op, [{name, "Start"}, {id, {20, 0, 1}}]},
        {op, [{name, "ShowPrime"}, {id, {20, 0, 2}}]},
        {op, [{name, "ShowNotPrime"}, {id, {20, 0, 3}}]},
        {index, [{id, {0, 0, 2}}],
         [{field, [{name, "div"}, {id, {10, 0, 4}}]},
          {field, [{name, "MAYBE"}, {id, {10, 0, 5}}]},
          {op, [{name, "FirstDivisor"}, {id, {20, 0, 4}}]},
          {op, [{name, "Test"}, {id, {20, 0, 5}}]},
          {op, [{name, "Iterate"}, {id, {20, 0, 6}}]}
           ]}]},
  ?OK_RETURN(R).

get_shallow_contents({folder, {0, 20, 1}}) ->
  R = [
        ?OK_RESULT(get_record({field, {10, 0, 1}})),
        ?OK_RESULT(get_record({field, {10, 0, 2}})),
        ?OK_RESULT(get_record({field, {10, 0, 3}})),
        ?OK_RESULT(get_record({op, {20, 0, 1}})),
        ?OK_RESULT(get_record({op, {20, 0, 2}})),
        ?OK_RESULT(get_record({op, {20, 0, 3}}))],
  ?OK_RETURN(R);

get_shallow_contents({folder, {0, 0, 2}}) ->
  R = [
        ?OK_RESULT(get_record({field, {10, 0, 4}})),
        ?OK_RESULT(get_record({field, {10, 0, 5}})),
        ?OK_RESULT(get_record({op, {20, 0, 4}})),
        ?OK_RESULT(get_record({op, {20, 0, 5}})),
        ?OK_RESULT(get_record({op, {20, 0, 6}}))],
  ?OK_RETURN(R).

get_deep_contents({folder, {0, 20, 1}}) ->
  R = [
        ?OK_RESULT(get_record({field, {10, 0, 1}})),
        ?OK_RESULT(get_record({field, {10, 0, 2}})),
        ?OK_RESULT(get_record({field, {10, 0, 3}})),
        ?OK_RESULT(get_record({op, {20, 0, 1}})),
        ?OK_RESULT(get_record({op, {20, 0, 2}})),
        ?OK_RESULT(get_record({op, {20, 0, 3}})),
        ?OK_RESULT(get_record({field, {10, 0, 4}})),
        ?OK_RESULT(get_record({field, {10, 0, 5}})),
        ?OK_RESULT(get_record({op, {20, 0, 4}})),
        ?OK_RESULT(get_record({op, {20, 0, 5}})),
        ?OK_RESULT(get_record({op, {20, 0, 6}}))],
  ?OK_RETURN(R);

get_deep_contents({folder, {0, 0, 2}}) ->
  R = [
        ?OK_RESULT(get_record({field, {10, 0, 4}})),
        ?OK_RESULT(get_record({field, {10, 0, 5}})),
        ?OK_RESULT(get_record({op, {20, 0, 4}})),
        ?OK_RESULT(get_record({op, {20, 0, 5}})),
        ?OK_RESULT(get_record({op, {20, 0, 6}}))],
  ?OK_RETURN(R).

%% Returns dummy new operation with no compositional root folder.
new_record(_Parent, _Name, #?FIELD{} = R) ->
  ?OK_RETURN(R#?FIELD{id = ?RANDOM_ID});
new_record(_Parent, _Name, #?FOLDER{} = R) ->
  ?OK_RETURN(R#?FOLDER{id = ?RANDOM_ID});
new_record(_Parent, _Name, #?OP{} = R) ->
  ?OK_RETURN(R#?OP{id = ?RANDOM_ID}).

snapshot(_Ref) ->
  snapshot(_Ref, "Version").

snapshot(_Ref, Label) ->
  ?OK_RETURN(#?OP{id = ?RANDOM_ID,
                  isComposite = true,
                  rootFolderRef = ?RANDOM_REF(?FOLDER),
                  versions = [
                               {2, Label, ?RANDOM_REF(?FOLDER)},
                               {1, "Initial release", ?RANDOM_REF(?FOLDER)}]}).

%%% ----------------------------------------------------------------------------
%%% UTILITY FUNCTIONS
%%% ----------------------------------------------------------------------------

%% Record to ref is for real.
record_to_ref(R) ->
  prog:record_to_ref(R).
